import static org.junit.Assert.*;

import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;


public class LinkedListTest {

	LinkedList testList;
	LinkedList testList2;
	PrintStream originalOut;
	ByteArrayOutputStream outContent;
	
	
	@Before
	public void setUp() throws Exception {
		 testList = new LinkedList();
		 testList2 = new LinkedList();
		 originalOut = System.out;
		 outContent = new ByteArrayOutputStream();
		 System.setOut(new PrintStream(outContent));
	}

	@After
	public void tearDown() throws Exception {
		System.setOut(originalOut);
		
		
	}

	@Test
	public void testInsert() {
		//first value
	 	testList.insert(1);
	 	int startValue = testList.start.getData();
	 	Assert.assertEquals(startValue, 1);
		 	 
	 	//second value
	 	testList.insert(2);
	 	int secondValue = testList.start.getNext().getData();
		Assert.assertEquals(secondValue, 2);
		 	 
	 	//third value
	 	testList.insert(3);
	 	int thirdValue = testList.start.getNext().getNext().getData();
	 	Assert.assertEquals(thirdValue, 3);
		 	 
	 	//fourth value -- negative value boundary case
	 	testList.insert(-4);
	 	int fourthValue = testList.start.getNext().getNext().getNext().getData();
	 	Assert.assertEquals(fourthValue, -4);
		 	 
	 	//fifth value -- 0 value boundary case
	 	testList.insert(0);
	 	int fifthValue = testList.start.getNext().getNext().getNext().getNext().getData();
	 	Assert.assertEquals(fifthValue, 0);
		 	 
	 	//sixth value -- duplicate value
	 	testList.insert(2);
	 	int sixthValue = testList.start.getNext().getNext().getNext().getNext().getNext().getData();
	 	Assert.assertEquals(sixthValue, 2);
}

	@Test
	public void testDelete() {


		//Insert values to delete
		testList2.insert(1);
		testList2.insert(2);
		testList2.insert(3);
		testList2.insert(-1);
		testList2.insert(-2);

		
	 	//Verify that number not in list works		
 		int x = 0;
		testList2.delete(x);
		String test = outContent.toString();
		String verify = "\nElement "+ x + " not found !";
		Assert.assertEquals(test, verify);
		
		testList.insert(1);
		testList.insert(2);
		testList.insert(3);
		testList.insert(-1);
		testList.insert(-2);
		testList.insert(0);
		testList.insert(2);

	//Delete negative value
	//4th location {1, 2, 3, -1, -2, 0, 2}
		
		//get initial values for placement locations
		int firstValue = testList.start.getData();
		int secondValue = testList.start.getNext().getData();
		int thirdValue = testList.start.getNext().getNext().getData();
		int fourthValue = testList.start.getNext().getNext().getNext().getData();
		int fifthValue = testList.start.getNext().getNext().getNext().getNext().getData();
		int sixthValue = testList.start.getNext().getNext().getNext().getNext().getNext().getData();
		int seventhValue = testList.start.getNext().getNext().getNext().getNext().getNext().getNext().getData();
		
		//run function
		testList.delete(-1);
		
		//get values after function ran
		int verifyFirstValue = testList.start.getData();
		int verifySecondValue = testList.start.getNext().getData();
		int verifyThirdValue = testList.start.getNext().getNext().getData();
		int verifyFourthValue = testList.start.getNext().getNext().getNext().getData();
		int verifyFifthValue = testList.start.getNext().getNext().getNext().getNext().getData();
		int verifySixthValue = testList.start.getNext().getNext().getNext().getNext().getNext().getData();
		
		//compare values from before and after function ran
		Assert.assertEquals(firstValue, verifyFirstValue);
		Assert.assertEquals(secondValue, verifySecondValue);
		Assert.assertEquals(thirdValue, verifyThirdValue);
		Assert.assertNotEquals(fourthValue, verifyFourthValue);
		Assert.assertEquals(fifthValue, verifyFourthValue);
		Assert.assertNotEquals(fifthValue, verifyFifthValue);
		Assert.assertEquals(sixthValue, verifyFifthValue);
		Assert.assertNotEquals(sixthValue, verifySixthValue);
		Assert.assertEquals(seventhValue, verifySixthValue);
	 	try{
	 		int verifySeventhValue = testList.start.getNext().getNext().getNext().getNext().getNext().getNext().getData();
	 		fail("Should have thrown an exeception");
	 	}
	 	catch (NullPointerException expected){
	 		
	 	}
		
	//Delete positive value
	//list should have 6 values {1, 2, 3, -2, 0, 2}
	//2nd location
		
		//get initial values for placement locations
		firstValue = testList.start.getData();
		secondValue = testList.start.getNext().getData();
		thirdValue = testList.start.getNext().getNext().getData();
		fourthValue = testList.start.getNext().getNext().getNext().getData();
		fifthValue = testList.start.getNext().getNext().getNext().getNext().getData();
		sixthValue = testList.start.getNext().getNext().getNext().getNext().getNext().getData();

		//run function
		testList.delete(2);
		
		//get values after function ran
		verifyFirstValue = testList.start.getData();
		verifySecondValue = testList.start.getNext().getData();
		verifyThirdValue = testList.start.getNext().getNext().getData();
		verifyFourthValue = testList.start.getNext().getNext().getNext().getData();
		verifyFifthValue = testList.start.getNext().getNext().getNext().getNext().getData();
		
		//compare values from before and after function ran
		Assert.assertEquals(firstValue, verifyFirstValue);
		Assert.assertNotEquals(secondValue, verifySecondValue);
		Assert.assertEquals(thirdValue, verifySecondValue);
		Assert.assertNotEquals(thirdValue, verifyThirdValue);
		Assert.assertEquals(fourthValue, verifyThirdValue);
		Assert.assertNotEquals(fourthValue, verifyFourthValue);
		Assert.assertEquals(fifthValue, verifyFourthValue);
		Assert.assertNotEquals(fifthValue, verifyFifthValue);
		Assert.assertEquals(sixthValue, verifyFifthValue);
	 	try{
	 		verifySixthValue = testList.start.getNext().getNext().getNext().getNext().getNext().getData();
	 		fail("Should have thrown an exeception");
	 	}
	 	catch (NullPointerException expected){
	 		
	 	}
		

	//Delete duplicate value
	//list should have 5 values {1, 3, -2, 0, 2}
	//5th location

		//get initial values for placement locations
		firstValue = testList.start.getData();
		secondValue = testList.start.getNext().getData();
		thirdValue = testList.start.getNext().getNext().getData();
		fourthValue = testList.start.getNext().getNext().getNext().getData();
		fifthValue = testList.start.getNext().getNext().getNext().getNext().getData();
		
		//run function
		testList.delete(2);
		
		//get values after function ran
		verifyFirstValue = testList.start.getData();
		verifySecondValue = testList.start.getNext().getData();
		verifyThirdValue = testList.start.getNext().getNext().getData();
		verifyFourthValue = testList.start.getNext().getNext().getNext().getData();
		
		//compare values from before and after function ran
		Assert.assertEquals(firstValue, verifyFirstValue);
		Assert.assertEquals(secondValue, verifySecondValue);
		Assert.assertEquals(thirdValue, verifyThirdValue);
		Assert.assertEquals(fourthValue, verifyFourthValue);
	 	try{
	 		verifyFifthValue = testList.start.getNext().getNext().getNext().getNext().getData();
	 		fail("Should have thrown an exeception");
	 	}
	 	catch (NullPointerException expected){
	 		
	 	}
		
	//Delete zero
	//list should have 4 values {1, 3, -2, 0}
	//4th location
		
		//get initial values for placement locations
		firstValue = testList.start.getData();
		secondValue = testList.start.getNext().getData();
		thirdValue = testList.start.getNext().getNext().getData();
		fourthValue = testList.start.getNext().getNext().getNext().getData();
		
		//run function
		testList.delete(0);
		
		//get values after function ran
		verifyFirstValue = testList.start.getData();
		verifySecondValue = testList.start.getNext().getData();
		verifyThirdValue = testList.start.getNext().getNext().getData();
		
		//compare values from before and after function ran
		Assert.assertEquals(firstValue, verifyFirstValue);
		Assert.assertEquals(secondValue, verifySecondValue);
		Assert.assertEquals(thirdValue, verifyThirdValue);
	 	try{
	 		verifyFourthValue = testList.start.getNext().getNext().getNext().getNext().getData();
	 		fail("Should have thrown an exeception");
	 	}
	 	catch (NullPointerException expected){
	 		
	 	}
		
			
		//Verify delete of empty list works.
	 	LinkedList lnklst = new LinkedList();
	 	
	 	//Assert.assertNull(null, lnklst.delete(0));
	 	try{
	 		lnklst.delete(0);
	 		fail("Should have thrown an exeception");
	 	}
	 	catch (NullPointerException expected){
	 		
	 	}
		
	}

}